home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
SciAn
/
src
/
ScianTextBoxes.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
72KB
|
2,785 lines
/* ScianTextBoxes.c
Routines for text boxes
J. Lyons
9/28/90
3/26/91 added simple editing
3/28/91 added routines to set font, size, line spacing
3/29/91 added provision for different style text boxes
4/19/91 added one-line editing
5/13/91 EMP moved an #ifdef FONTS4D around a fontHandle
5/29/91 EMP removed lib headers
7/17/91 added multiline editing
7/22/91 added incredibly fancy frame for adjustable text boxes
8/12/91 modified to use ScianFontSystem routines
8/16/91 modified to use Set/Get2DIntBounds
8/27/91 added ACTIVATED attribute
8/28/91 added CUT, COPY, PASTE methods
9/5/91 added TextHeight routine
9/6/91 added help
10/30/91 added shift-clicking to press method
11/1/91 added double-clicking to press method
11/4/91 added control window for textboxes (with EMP)
1/8/92 added indentation control
1/20/92 fixed linespace problem for large sizes
1/22/92 made indentation behavior more like tabs, sort of
4/9/92 EMP removed argument from NEWCTLWINDOW method
6/13/92 EMP changed method prototypes to declarations
8/30/92 EMP added opacity dependency and make method
12/3/92 changed Press routine per new selection scheme
12/8/92 added auto horiz scrolling to one-line text boxes
1/21/93 did undo
3/2/93 rewrote code for one-line textboxes to clean up auto-scrolling
*/
#include "Scian.h"
#include "ScianStyle.h"
#include "ScianTypes.h"
#include "ScianFontSystem.h"
#include "ScianWindows.h"
#include "ScianArrays.h"
#include "ScianLists.h"
#include "ScianDraw.h"
#include "ScianColors.h"
#include "ScianIDs.h"
#include "ScianErrors.h"
#include "ScianEvents.h"
#include "ScianScripts.h"
#include "ScianMethods.h"
#include "ScianDialogs.h"
#include "ScianControls.h"
#include "ScianHelp.h"
#include "ScianTitleBoxes.h"
#include "ScianTextBoxes.h"
#include "ScianSliders.h"
#include "ScianButtons.h"
#include "ScianDrawings.h"
#include "ScianSymbols.h"
#include "ScianSnap.h"
/* #define NEWWAY */
#define MAXLINE 255
#define MAXNLINES 20
#define MAXTEXTSIZE 96
/* Method declarations, NOT prototypes */
static ObjPtr EditTextBox();
static ObjPtr DrawTextBox();
static ObjPtr DrawOneLiner();
static ObjPtr PressTextBox();
static ObjPtr PressOneLiner();
static ObjPtr ShowTextBoxControls();
static ObjPtr TextBoxNotCurrent();
static ObjPtr CutText();
static ObjPtr CopyText();
static ObjPtr PasteText();
static ObjPtr MakeHelpString();
static ObjPtr SetTBVal();
static ObjPtr MakeTextBoxOpaque();
/* static function prototypes */
#ifdef PROTO
static void NewText(ObjPtr);
static char *NextLine(char *, int, char *);
#else
static void NewText();
static char *NextLine();
#endif
/*********************************************************************** GLOBALS */
ObjPtr textBoxClass;
static char *textBuf; /* pointer to buffer for drawing and editing text */
static int textBufSize; /* current size of the buffer */
static int indent; /* current indent amount, in pixels */
#define TEXTBUFFERSIZE 1000
#define TEXTBUFFERINCR 100
void InitTextBoxes()
{
ObjPtr list;
textBoxClass = NewObject(controlClass, 0);
AddToReferenceList(textBoxClass);
SetVar(textBoxClass, NAME, NewString("Text Box"));
SetVar(textBoxClass, TYPESTRING, NewString("text box"));
SetVar(textBoxClass, TEXTFONT, NewString("Helvetica"));
SetVar(textBoxClass, TEXTSIZE, NewInt(12));
SetMethod(textBoxClass, DRAW, DrawTextBox);
SetMethod(textBoxClass, SETVAL, SetTBVal);
SetMethod(textBoxClass, PRESS, PressTextBox);
SetMethod(textBoxClass, KEYDOWN, EditTextBox);
SetMethod(textBoxClass, CUT, CutText);
SetMethod(textBoxClass, COPY, CopyText);
SetMethod(textBoxClass, PASTE, PasteText);
SetMethod(textBoxClass, SELECTALL, SelectAll);
SetMethod(textBoxClass, PICKUP, (FuncTyp) 0);
SetMethod(textBoxClass, MAKE1HELPSTRING, MakeHelpString);
SetMethod(textBoxClass, NEWCTLWINDOW, ShowTextBoxControls);
SetMethod(textBoxClass, YOURENOTCURRENT, TextBoxNotCurrent);
SetMethod(textBoxClass, ALIGNLEFT, AlignLeft);
SetMethod(textBoxClass, ALIGNCENTER, AlignCenter);
SetMethod(textBoxClass, ALIGNRIGHT, AlignRight);
SetMethod(textBoxClass, SETTEXTSIZE, SetTextSizeMethod);
SetMethod(textBoxClass, SETTEXTFONT, SetTextFontMethod);
/* stuff for undo to work */
list = NewList();
PrefixList(list, NewSymbol(BOUNDS));
PrefixList(list, NewSymbol(BGNSEL));
PrefixList(list, NewSymbol(ENDSEL));
PrefixList(list, NewSymbol(TEXTFONT));
PrefixList(list, NewSymbol(TEXTSIZE));
PrefixList(list, NewSymbol(LINESPACE));
PrefixList(list, NewSymbol(ALIGNMENT));
PrefixList(list, NewSymbol(COLOR));
PrefixList(list, NewSymbol(BACKGROUND));
PrefixList(list, NewSymbol(LASTKEY));
PrefixList(list, NewSymbol(VALUE));
SetVar(textBoxClass, SNAPVARS, list);
/*EMP stuff for opacity to work*/
DeclareDependency(textBoxClass, OPAQUE, BACKGROUND);
SetMethod(textBoxClass, OPAQUE, MakeTextBoxOpaque);
/* get a buffer for drawing and editing text */
textBuf = (char *) Alloc(textBufSize = TEXTBUFFERSIZE);
if (!textBuf)
{
OMErr();
textBufSize = 0;
}
}
void KillTextBoxes()
{
DeleteThing(textBoxClass);
if (textBuf) Free(textBuf);
}
static ObjPtr MakeTextBoxOpaque(textBox)
ObjPtr textBox;
/*EMP - Makes a text box's OPAQUE variable*/
{
SetVar(textBox, OPAQUE, GetVar(textBox, BACKGROUND) ? ObjTrue : ObjFalse);
return ObjTrue;
}
#ifdef PROTO
ObjPtr NewTextBox(int left, int right, int bottom , int top,
int style, char *name, char *text)
#else
ObjPtr NewTextBox(left, right, bottom, top, style, name, text)
int left, right, bottom, top, style;
char *name, *text;
#endif
{
ObjPtr newBox;
if (left > right)
{
register int n;
n = left; left = right; right = n;
}
if (bottom > top)
{
register int n;
n = bottom; bottom = top; top = n;
}
newBox = NewObject(textBoxClass, 0);
Set2DIntBounds(newBox, left, right, bottom, top);
SetVar(newBox, CLASSID, NewInt(CLASS_TEXTBOX));
SetVar(newBox, ACTIVATED, NewInt(true));
SetVar(newBox, STYLE, NewInt(style));
SetVar(newBox, NAME, NewString(name));
if (style & WITH_PIT) SetVar(newBox, BACKGROUND, NewInt(TEXTBOXCOLOR));
SetVar(newBox, VALUE, NewString(text));
SetVar(newBox, CHANGED, ObjTrue); /* flag to line-break text before drawing first time */
if (style & EDITABLE)
{
ObjPtr theLen = NewInt(strlen(text));
SetVar(newBox, BGNSEL, theLen);
SetVar(newBox, ENDSEL, theLen);
}
if (style & ONE_LINE)
{
SetMethod(newBox, DRAW, DrawOneLiner);
SetMethod(newBox, PRESS, PressOneLiner);
SetVar(newBox, FORWARDVECTOR, ObjTrue); /* for auto-scroll */
SetVar(newBox, HOROFFSET, NewInt(0));
}
return newBox;
}
static ObjPtr MakeHelpString(textBox, theClass)
ObjPtr textBox, theClass;
{
int style = GetInt(GetVar(textBox, STYLE));
*textBuf = '\0';
if (style & EDITABLE) strcpy(textBuf,"This is an editable text box. \
Click the left mouse button anywhere in the text to place the insertion point \
for adding new text. Drag through text to select it for editing. ");
if (style & ADJUSTABLE) strcat(textBuf, "To change the size or location \
of this text box, first click anywhere in the text to select it. A frame will \
appear around the text with eight small handles. Drag any of the handles to change \
the size of the text box. Drag the frame itself to reposition the text.");
if (style & ONE_LINE) strcat(textBuf, "If all the text will not fit \
within the box, it will automatically scroll as you add or delete text, drag \
through text to select it, or use the arrow keys to move the insertion point.");
SetVar(theClass, HELPSTRING, *textBuf ? NewString(textBuf) : NULLOBJ);
return ObjTrue;
}
#ifdef PROTO
void ActivateTextBox(ObjPtr textBox, Bool act)
#else
void ActivateTextBox(textBox, act)
ObjPtr textBox;
Bool act;
#endif
{
if (act) SetVar(textBox, ACTIVATED, ObjTrue);
else
{
SetVar(textBox, ACTIVATED, ObjFalse);
Select(textBox, false);
}
ImInvalid(textBox);
}
static ObjPtr SetTBVal(textBox, theText)
ObjPtr textBox, theText;
{
Bool deferChange;
if (IsString(theText)) SetTextBox(textBox, GetString(theText));
else if (IsInt(theText))
{
sprintf(tempStr, "%d", GetInt(theText));
SetTextBox(textBox, tempStr);
}
else if (IsReal(theText))
{
sprintf(tempStr, "%g", GetReal(theText));
SetTextBox(textBox, tempStr);
}
else return ObjFalse;
return ObjTrue;
}
/******************************************************************** SET TEXT ROUTINES */
#ifdef PROTO
ObjPtr SetTextBox(ObjPtr textBox, char *text)
#else
ObjPtr SetTextBox(textBox, text)
ObjPtr textBox;
char *text;
#endif
{
int style;
style = GetInt(GetVar(textBox, STYLE));
SetVar(textBox, VALUE, NewString(text));
if (style & EDITABLE)
{
ObjPtr theLen = NewInt(strlen(text));
SetVar(textBox, BGNSEL, theLen);
SetVar(textBox, ENDSEL, theLen);
}
if (style & ONE_LINE)
{
SetVar(textBox, HOROFFSET, NewInt(0));
SetVar(textBox, FORWARDVECTOR, ObjTrue);
}
SetVar(textBox, CHANGED, ObjTrue);
ImInvalid(textBox);
ChangedValue(textBox);
if (logging) LogControl(textBox);
return NULLOBJ;
}
#ifdef PROTO
ObjPtr SetTextFont(ObjPtr textBox, char *fontName)
#else
ObjPtr SetTextFont(textBox, fontName)
ObjPtr textBox;
char *fontName;
#endif
{
SetVar(textBox, TEXTFONT, NewString(fontName));
SetVar(textBox, CHANGED, ObjTrue);
ImInvalid(textBox);
return NULLOBJ;
}
#ifdef PROTO
ObjPtr SetTextSize(ObjPtr textBox, int textSize)
#else
ObjPtr SetTextSize(textBox, textSize)
ObjPtr textBox;
int textSize;
#endif
{
if (textSize > 0 && textSize <= MAXTEXTSIZE)
SetVar(textBox, TEXTSIZE, NewInt(textSize));
SetVar(textBox, CHANGED, ObjTrue);
ImInvalid(textBox);
return NULLOBJ;
}
ObjPtr SetTextSizeMethod(textBox, textSize)
ObjPtr textBox;
ObjPtr textSize;
/*Method for setting text size. textSize is a string or integer or real.
Don't ask why.*/
{
char *s;
int n;
if (IsInt(textSize) || IsReal(textSize))
{
n = GetInt(textSize);
}
else if (IsString(textSize))
{
if (1 != sscanf(GetString(textSize), "%d", &n))
{
ReportError("SetTextSizeMethod", "String is not a number");
return ObjFalse;
}
}
else
{
ReportError("SetTextSizeMethod", "Value is not an integer or string");
return ObjFalse;
}
SetTextSize(textBox, n);
return ObjTrue;
}
ObjPtr SetTextFontMethod(textBox, textFont)
ObjPtr textBox;
ObjPtr textFont;
/*Method for setting text font. textFont is a STRING.*/
{
char *s;
s = GetString(textFont);
if (s)
{
SetTextFont(textBox, s);
}
return ObjTrue;
}
#ifdef PROTO
ObjPtr SetTextLineSpace(ObjPtr textBox, int lineSpace)
#else
ObjPtr SetTextSize(textBox, lineSpace)
ObjPtr textBox;
int lineSpace;
#endif
{
if (lineSpace > 0)
SetVar(textBox, LINESPACE, NewInt(lineSpace));
ImInvalid(textBox);
return NULLOBJ;
}
/*Methods for individual alignment*/
#ifdef PROTO
ObjPtr SetTextAlign(ObjPtr textBox, int value)
#else
ObjPtr SetTextAlign(textBox, value)
ObjPtr textBox;
int value;
#endif
{
SetVar(textBox, ALIGNMENT, NewInt(value));
ImInvalid(textBox);
return NULLOBJ;
}
ObjPtr AlignLeft(textBox)
ObjPtr textBox;
/*Aligns a text box left*/
{
SetTextAlign(textBox, LEFTALIGN);
return ObjTrue;
}
ObjPtr AlignCenter(textBox)
ObjPtr textBox;
/*Aligns a text box left*/
{
SetTextAlign(textBox, CENTERALIGN);
return ObjTrue;
}
ObjPtr AlignRight(textBox)
ObjPtr textBox;
/*Aligns a text box left*/
{
SetTextAlign(textBox, RIGHTALIGN);
return ObjTrue;
}
#ifdef PROTO
ObjPtr SetTextColor(ObjPtr textBox, ObjPtr color)
#else
ObjPtr SetTextColor(textBox, color)
ObjPtr textBox, color;
#endif
{
SetVar(textBox, COLOR, color);
ImInvalid(textBox);
return NULLOBJ;
}
#ifdef PROTO
ObjPtr SetTextBGColor(ObjPtr textBox, ObjPtr color)
#else
ObjPtr SetTextBGColor(textBox, color)
ObjPtr textBox, color;
#endif
{
SetVar(textBox, BACKGROUND, color);
ImInvalid(textBox);
return NULLOBJ;
}
#ifdef PROTO
ObjPtr SetTextBoxStyle(ObjPtr textBox, int style)
#else
ObjPtr SetTextBoxStyle(textBox, style)
ObjPtr textBox;
int style;
#endif
{
SetVar(textBox, STYLE, NewInt(style));
if (style & ONE_LINE)
{
SetMethod(textBox, DRAW, DrawOneLiner);
SetMethod(textBox, PRESS, PressOneLiner);
SetVar(textBox, FORWARDVECTOR, ObjTrue); /* for auto-scroll */
SetVar(textBox, HOROFFSET, NewInt(0));
SetVar(textBox, FORWARDVECTOR, ObjTrue);
}
else
{
SetMethod(textBox, DRAW, DrawTextBox);
SetMethod(textBox, PRESS, PressTextBox);
SetVar(textBox, FORWARDVECTOR, NULLOBJ);
SetVar(textBox, HOROFFSET, NULLOBJ);
SetVar(textBox, FORWARDVECTOR, NULLOBJ);
}
SetVar(textBox, CHANGED, ObjTrue);
ImInvalid(textBox);
return NULLOBJ;
}
#ifdef NEWWAY
/*********************************************************** NEW TEXT */
#ifdef PROTO
static void NewText(ObjPtr textBox)
#else
static void NewText(textBox)
ObjPtr textBox;
#endif
{
/* puts "soft" eols (\r is used) into the text as needed */
int left, right, bottom, top;
int textLeft, textRight;
ObjPtr theObj;
char *text, *nxtLine, *bgnLine, *s, *t, *fontName, lineBuf[MAXLINE + 1];
int len, width, size, style;
Get2DIntBounds(textBox, &left, &right, &bottom, &top);
MakeVar(textBox, VALUE);
text = GetString(GetVar(textBox, VALUE));
theObj = GetVar(textBox, STYLE);
if (theObj) style = GetInt(theObj);
else style = PLAIN;
if (style & ONE_LINE)
{
SetVar(textBox, VALUE, NewString(text));
return;
}
theObj = GetVar(textBox, TEXTFONT);
if (theObj) fontName = GetString(theObj);
else fontName = DEFFONT;
theObj = GetVar(textBox, TEXTSIZE);
if (theObj) size = GetInt(theObj);
else size = DEFTEXTSIZE;
if (style & WITH_PIT)
{
textLeft = left + TEXTMARGIN;
textRight = right - TEXTMARGIN;
}
else if (style & (EDITABLE | ADJUSTABLE) || GetVar(textBox, BACKGROUND))
{
textLeft = left + HANDLESIZE + 2;
textRight = right - HANDLESIZE - 2;
}
else /* default is no inset */
{
textLeft = left;
textRight = right;
}
/*** CHANGE FOR INDENTATION ***/
SetupFont(fontName, size);
width = textRight - textLeft;
nxtLine = text; /* set up for loop */
t = textBuf;
do {
if (t - textBuf + MAXLINE > textBufSize) /* increase buffer size */
{
int tIndex = t - textBuf; /* remember position */
textBuf = (char *) Realloc(textBuf, textBufSize + TEXTBUFFERINCR);
if (!textBuf) /* failed */
{
OMErr();
textBufSize = 0;
return;
}
t = tIndex + textBuf; /* reset pointer in new buffer */
}
bgnLine = nxtLine;
nxtLine = NextLine(bgnLine, width, s=lineBuf); /* (ignores existing soft CRs) */
while (*t++ = *s++) ; /* copy line into textBuf */
--t; /* back up to terminator */
if (*nxtLine == '\n') ++nxtLine, *t++ = '\n'; /* paragraph */
else *t++ = '\r'; /* soft eol */
} while (*nxtLine);
*t = '\0'; /* stuff terminator */
SetVar(textBox, VALUE, NewString(textBuf));
SetVar(textBox, CHANGED, ObjFalse);
/* calling routine will handle draw, changed value */
}
#endif
/*********************************************************** TEXT HEIGHT */
#ifdef PROTO
int TextHeight(ObjPtr textBox)
#else
int TextHeight(textBox)
ObjPtr textBox;
#endif
{
#ifndef NEWWAY
int left, right, bottom, top;
int textLeft, textRight, textTop;
ObjPtr theObj;
char *text, *nxtLine, *bgnLine, lineBuf[MAXLINE + 1], *fontName;
int uiFont, y, width, size, align, lineSpace, style;
int tabWid;
Bool uiTB = false;
Get2DIntBounds(textBox, &left, &right, &bottom, &top);
MakeVar(textBox, VALUE);
theObj = GetVar(textBox, VALUE);
if (theObj) text = GetString(theObj);
else text = "\0";
theObj = GetVar(textBox, STYLE);
if (theObj) style = GetInt(theObj);
else style = PLAIN;
theObj = GetVar(textBox, UIFONT);
if (theObj)
{
uiFont = GetInt(theObj);
size = uiFontInfo[uiFont].size;
uiTB = true;
}
else
{
theObj = GetStringVar("TextHeight", textBox, TEXTFONT);
if (theObj) fontName = GetString(theObj);
else return 0;
theObj = GetIntVar("TextHeight", textBox, TEXTSIZE);
if (theObj) size = GetInt(theObj);
else return 0;
}
theObj = GetVar(textBox, ALIGNMENT);
if (theObj) align = GetInt(theObj);
else align = LEFTALIGN;
theObj = GetVar(textBox, LINESPACE);
if (theObj) lineSpace = GetInt(theObj);
else lineSpace = 4 + size/3;
MakeVar(textBox, BACKGROUND);
if (style & WITH_PIT)
{
textLeft = left + TEXTMARGIN;
textRight = right - TEXTMARGIN;
textTop = top - TEXTMARGIN;
}
else if (style & (EDITABLE | ADJUSTABLE) || GetVar(textBox, BACKGROUND))
{
textLeft = left + HANDLESIZE + 2;
textRight = right - HANDLESIZE - 2;
textTop = top - HANDLESIZE - 2;
}
else /* default is no inset */
{
textLeft = left;
textRight = right;
textTop = top;
}
if (uiTB)
{
SetUIFont(uiFont);
}
else
{
SetupFont(fontName, size);
}
tabWid = TABWID*ChrWidth('0');
y = textTop - size;
width = textRight - textLeft;
indent = 0;
bgnLine = nxtLine = text; /* set up for loop */
do {
bgnLine = nxtLine;
nxtLine = NextLine(bgnLine, width - indent, lineBuf);
y -= size + lineSpace;
if (*nxtLine == '\n')
{
++nxtLine; /* paragraph */
indent = 0;
}
else indent += ChrCount(lineBuf, '\t')*tabWid;
} while (*nxtLine);
return textTop - y + size;
#else
ObjPtr theObj;
int n, size, lineSpace;
char *t;
if (GetPredicate(textBox, CHANGED)) NewText(textBox);
MakeVar(textBox, VALUE);
t = GetString(GetVar(textBox, VALUE));
theObj = GetVar(textBox, TEXTSIZE);
if (theObj) size = GetInt(theObj);
else size = DEFTEXTSIZE;
theObj = GetVar(textBox, LINESPACE);
if (theObj) lineSpace = GetInt(theObj);
else lineSpace = 4 + size/3;
n = 0;
while (*t)
{
if (*t == '\r' || *t == '\n') ++n;
++t;
}
return n*(size + lineSpace);
#endif
}
int ChrCount(s, c)
char *s, c;
{
int n=0;
while (*s) if (*s++ == c) ++n;
return n;
}
/************************************************************************** DRAW TEXT BOX */
static ObjPtr DrawTextBox(textBox)
ObjPtr textBox;
{
#ifdef GRAPHICS
Bool active;
int left, right, bottom, top;
int textLeft, textRight, textBottom, textTop;
int x,y;
ObjPtr theObj, color, bgColor;
char *s, *t, *text, *nxtLine, *bgnLine, lineBuf[MAXLINE + 1], *fontName;
int lineStart, selStart, selEnd; /* distances for line and selection */
int bgnSel, endSel; /* index to text selection */
int uiFont, align, length, width, center, size, lineSpace, style;
int tabWid, nTabs;
Bool uiTB = false;
Get2DIntBounds(textBox, &left, &right, &bottom, &top);
if (IsDrawingRestricted(left, right, bottom, top)) return ObjFalse;
active = GetPredicate(textBox, ACTIVATED);
MakeVar(textBox, VALUE);
theObj = GetStringVar("DrawTextBox", textBox, VALUE);
if (theObj) text = GetString(theObj);
else text = "\0";
if ((length = strlen(text)) > textBufSize) /* grow buffer */
{
textBuf = (char *) Realloc(textBuf, length + TEXTBUFFERINCR);
if (!textBuf) /* failed */
{
OMErr();
textBufSize = 0;
return NULLOBJ;
}
}
theObj = GetIntVar("DrawTextBox", textBox, STYLE);
if (theObj) style = GetInt(theObj);
else style = PLAIN;
theObj = GetVar(textBox, ALIGNMENT);
if (theObj) align = GetInt(theObj);
else align = LEFTALIGN;
theObj = GetVar(textBox, UIFONT);
if (theObj)
{
uiFont = GetInt(theObj);
size = uiFontInfo[uiFont].size;
uiTB = true;
}
else
{
theObj = GetStringVar("DrawTextBox", textBox, TEXTFONT);
if (theObj) fontName = GetString(theObj);
else return ObjFalse;
theObj = GetIntVar("DrawTextBox", textBox, TEXTSIZE);
if (theObj) size = GetInt(theObj);
else return ObjFalse;
}
theObj = GetVar(textBox, LINESPACE);
if (theObj) lineSpace = GetInt(theObj);
else lineSpace = 4 + size/3;
MakeVar(textBox, COLOR);
color = GetVar(textBox, COLOR);
MakeVar(textBox, BACKGROUND);
bgColor = GetVar(textBox, BACKGROUND);
if (active && AmICurrent(textBox) && style & EDITABLE)
{
theObj = GetVar(textBox, BGNSEL);
if (theObj) bgnSel = GetInt(theObj);
else bgnSel = strlen(text);
theObj = GetVar(textBox, ENDSEL);
if (theObj) endSel = GetInt(theObj);
else endSel = bgnSel;
}
if (style & WITH_PIT)
{
DrawSunkenRect(left, right, bottom, top,
active ? TEXTBOXCOLOR : UIBACKGROUND);
textLeft = left + TEXTMARGIN;
textRight = right - TEXTMARGIN;
textBottom = bottom + TEXTMARGIN;
textTop = top - TEXTMARGIN;
}
else if (bgColor)
{
SetObjectColor(bgColor);
FillRect(left, right, bottom, top);
textLeft = left + HANDLESIZE + 2;
textRight = right - HANDLESIZE - 2;
textBottom = bottom + HANDLESIZE + 2;
textTop = top - HANDLESIZE - 2;
}
else if (style & (EDITABLE | ADJUSTABLE))
{
textLeft = left + HANDLESIZE + 2;
textRight = right - HANDLESIZE - 2;
textBottom = bottom + HANDLESIZE + 2;
textTop = top - HANDLESIZE - 2;
}
else /* default is no inset */
{
textLeft = left;
textRight = right;
textBottom = bottom;
textTop = top;
}
if (style & ADJUSTABLE) SetClipRect(left, right, bottom, top);
else SetClipRect(textLeft-1, textRight+1, textBottom-1, textTop+1);
/* wake up, time to draw */
if (uiTB)
{
SetUIFont(uiFont);
}
else
{
SetupFont(fontName, size);
}
y = textTop - size;
width = textRight - textLeft;
tabWid = TABWID*ChrWidth('0');
indent = 0;
center = (textLeft + textRight)/2;
nxtLine = text; /* set up for loop */
do {
bgnLine = nxtLine;
nxtLine = NextLine(bgnLine, width - indent, lineBuf);
length = StrWidth(lineBuf);
switch (align)
{
case CENTERALIGN:
lineStart = center - length/2;
break;
case RIGHTALIGN:
lineStart = textRight - length;
break;
case LEFTALIGN:
default:
lineStart = textLeft + indent;
break;
}
if (active && AmICurrent(textBox) && style & EDITABLE)
{
/* draw text cursor if in this line */
if (bgnSel == endSel && text + bgnSel <= nxtLine
&& text + bgnSel >= bgnLine)
{
/* find position of insertion point */
int i = bgnSel - (bgnLine - text);
strncpy(textBuf, bgnLine, i);
textBuf[i] = '\0';
selStart = StrWidth(textBuf);
/* draw text cursor before bgnSel */
FillUIRect(lineStart + selStart, lineStart + selStart + 1,
y - lineSpace + 2, y + size + 2, TEXTCURSORCOLOR);
}
else if (text + endSel > bgnLine && text + bgnSel < nxtLine)
{
int selectColor;
/* some of the selection is on this line */
if (text + bgnSel < bgnLine) selStart = lineStart;
else /* compute dist to start of selection */
{
int i = bgnSel - (bgnLine - text);
strncpy(textBuf, bgnLine, i);
textBuf[i] = '\0';
selStart = lineStart + StrWidth(textBuf);
}
if (text + endSel >= nxtLine) selEnd = lineStart + length;
else /* compute dist to end of selection */
{
int i = endSel - (bgnLine - text);
strncpy(textBuf, bgnLine, i);
textBuf[i] = '\0';
selEnd = lineStart + StrWidth(textBuf);
}
/* now draw the selection rectangle for this line */
selectColor = ChooseSelectionColor(textBox);
FillUIRect(selStart, selEnd, y - lineSpace + 2, y + size + 2,
selectColor);
}
}
/* now draw the text */
if (color) SetObjectColor(color);
else SetUIColor(UITEXT);
nTabs = 0; s = t = lineBuf; /* set up for loop */
while (true)
{
if (*t == '\0') /* end of line */
{
switch (align)
{
case CENTERALIGN:
DrawAString(CENTERALIGN, center, y, s);
break;
case RIGHTALIGN:
DrawAString(RIGHTALIGN, textRight, y, s);
break;
case LEFTALIGN:
default:
DrawAString(LEFTALIGN, lineStart, y, s);
break;
}
break;
}
else if (*t == '\t') /* handle tab */
{
*t = '\0'; /* stuff terminator for this segment */
DrawAString(LEFTALIGN, lineStart, y, s);
indent = (++nTabs)*tabWid;
lineStart = textLeft + indent;
s = ++t;
continue;
}
else ++t;
}
if ((y -= size + lineSpace) < textBottom) break; /* whoa! past bottom of box */
if (*nxtLine == '\n')
{
++nxtLine; /* paragraph */
indent = 0;
}
} while (*nxtLine);
if (IsSelected(textBox) && style & ADJUSTABLE)
{
/* Draw incredibly fancy frame for moving and resizing text box */
int horCent = (left + right)/2;
int vertCent = (bottom + top)/2;
#if 0
FrameUIWideRect(left+INSET, right-INSET,
bottom+INSET, top-INSET,
OUTSIDEFRAMEWEIGHT, OUTSIDEFRAMECOLOR);
FrameUIWideRect(left+INSET+OUTSIDEFRAMEWEIGHT,
right-INSET-OUTSIDEFRAMEWEIGHT,
bottom+INSET+OUTSIDEFRAMEWEIGHT,
top-INSET-OUTSIDEFRAMEWEIGHT,
INSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
FrameUIWideRect(left+INSET+OUTSIDEFRAMEWEIGHT+INSIDEFRAMEWEIGHT,
right-INSET-OUTSIDEFRAMEWEIGHT-INSIDEFRAMEWEIGHT,
bottom+INSET+OUTSIDEFRAMEWEIGHT+INSIDEFRAMEWEIGHT,
top-INSET-OUTSIDEFRAMEWEIGHT-INSIDEFRAMEWEIGHT,
OUTSIDEFRAMEWEIGHT, OUTSIDEFRAMECOLOR);
#else
FrameUIWideRect(left+INSET, right-INSET,
bottom+INSET, top-INSET,
2*OUTSIDEFRAMEWEIGHT + INSIDEFRAMEWEIGHT + 1,
OUTSIDEFRAMECOLOR);
FrameUIWideRect(left+INSET+OUTSIDEFRAMEWEIGHT,
right-INSET-OUTSIDEFRAMEWEIGHT,
bottom+INSET+OUTSIDEFRAMEWEIGHT,
top-INSET-OUTSIDEFRAMEWEIGHT,
INSIDEFRAMEWEIGHT + 1, INSIDEFRAMECOLOR);
#endif
/* Now draw the handles */
/* center of sides */
FillUIRect(left, left+HANDLESIZE,
vertCent-HANDLESIZE/2, vertCent+HANDLESIZE/2, OUTSIDEFRAMECOLOR);
FillUIRect(left+OUTSIDEFRAMEWEIGHT,
left+HANDLESIZE-OUTSIDEFRAMEWEIGHT,
vertCent-HANDLESIZE/2+OUTSIDEFRAMEWEIGHT,
vertCent+HANDLESIZE/2-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
FillUIRect(right-HANDLESIZE, right,
vertCent-HANDLESIZE/2, vertCent+HANDLESIZE/2, OUTSIDEFRAMECOLOR);
FillUIRect(right-HANDLESIZE+OUTSIDEFRAMEWEIGHT,
right-OUTSIDEFRAMEWEIGHT,
vertCent-HANDLESIZE/2+OUTSIDEFRAMEWEIGHT,
vertCent+HANDLESIZE/2-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
/* top edge */
FillUIRect(horCent-HANDLESIZE/2, horCent+HANDLESIZE/2,
top-HANDLESIZE, top, OUTSIDEFRAMECOLOR);
FillUIRect(horCent-HANDLESIZE/2+OUTSIDEFRAMEWEIGHT,
horCent+HANDLESIZE/2-OUTSIDEFRAMEWEIGHT,
top-HANDLESIZE+OUTSIDEFRAMEWEIGHT,
top-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
FillUIRect(left, left+HANDLESIZE,
top-HANDLESIZE, top, OUTSIDEFRAMECOLOR);
FillUIRect(left+OUTSIDEFRAMEWEIGHT,
left+HANDLESIZE-OUTSIDEFRAMEWEIGHT,
top-HANDLESIZE+OUTSIDEFRAMEWEIGHT,
top-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
FillUIRect(right-HANDLESIZE, right,
top-HANDLESIZE, top, OUTSIDEFRAMECOLOR);
FillUIRect(right-HANDLESIZE+OUTSIDEFRAMEWEIGHT,
right-OUTSIDEFRAMEWEIGHT,
top-HANDLESIZE+OUTSIDEFRAMEWEIGHT,
top-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
/* bottom edge */
FillUIRect(horCent-HANDLESIZE/2, horCent+HANDLESIZE/2,
bottom, bottom+HANDLESIZE, OUTSIDEFRAMECOLOR);
FillUIRect(horCent-HANDLESIZE/2+OUTSIDEFRAMEWEIGHT,
horCent+HANDLESIZE/2-OUTSIDEFRAMEWEIGHT,
bottom+OUTSIDEFRAMEWEIGHT,
bottom+HANDLESIZE-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
FillUIRect(left, left+HANDLESIZE,
bottom, bottom+HANDLESIZE, OUTSIDEFRAMECOLOR);
FillUIRect(left+OUTSIDEFRAMEWEIGHT,
left+HANDLESIZE-OUTSIDEFRAMEWEIGHT,
bottom+OUTSIDEFRAMEWEIGHT,
bottom+HANDLESIZE-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
FillUIRect(right-HANDLESIZE, right,
bottom, bottom+HANDLESIZE, OUTSIDEFRAMECOLOR);
FillUIRect(right-HANDLESIZE+OUTSIDEFRAMEWEIGHT,
right-OUTSIDEFRAMEWEIGHT,
bottom+OUTSIDEFRAMEWEIGHT,
bottom+HANDLESIZE-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
}
RestoreClipRect();
#endif
return ObjTrue;
}
static ObjPtr DrawOneLiner(textBox)
ObjPtr textBox;
{
#ifdef GRAPHICS
Bool active, showEnd;
int left, right, bottom, top;
int textLeft, textRight, textBottom, textTop;
ObjPtr theObj, color, bgColor;
char *fontName, *text;
int lineStart, selStart, selEnd; /* distances for line and selection */
int bgnSel, endSel; /* index to text selection */
int uiFont, align, length, center, size, style, horOffset;
Bool uiTB = false;
Get2DIntBounds(textBox, &left, &right, &bottom, &top);
if (IsDrawingRestricted(left, right, bottom, top)) return ObjFalse;
active = GetPredicate(textBox, ACTIVATED);
MakeVar(textBox, VALUE);
theObj = GetStringVar("DrawTextBox", textBox, VALUE);
if (theObj) text = GetString(theObj);
else text = "\0";
theObj = GetIntVar("DrawTextBox", textBox, STYLE);
if (theObj) style = GetInt(theObj);
else style = PLAIN;
theObj = GetVar(textBox, ALIGNMENT);
if (theObj) align = GetInt(theObj);
else align = LEFTALIGN;
theObj = GetVar(textBox, UIFONT);
if (theObj)
{
uiFont = GetInt(theObj);
size = uiFontInfo[uiFont].size;
uiTB = true;
}
else
{
theObj = GetStringVar("DrawTextBox", textBox, TEXTFONT);
if (theObj) fontName = GetString(theObj);
else return ObjFalse;
theObj = GetIntVar("DrawTextBox", textBox, TEXTSIZE);
if (theObj) size = GetInt(theObj);
else return ObjFalse;
}
theObj = GetVar(textBox, HOROFFSET);
if (theObj) horOffset = GetInt(theObj);
else horOffset = 0;
MakeVar(textBox, COLOR);
color = GetVar(textBox, COLOR);
MakeVar(textBox, BACKGROUND);
bgColor = GetVar(textBox, BACKGROUND);
if (active && AmICurrent(textBox) && style & EDITABLE)
{
theObj = GetVar(textBox, BGNSEL);
if (theObj) bgnSel = GetInt(theObj);
else bgnSel = strlen(text);
theObj = GetVar(textBox, ENDSEL);
if (theObj) endSel = GetInt(theObj);
else endSel = bgnSel;
}
if (style & WITH_PIT)
{
DrawSunkenRect(left, right, bottom, top,
active ? TEXTBOXCOLOR : UIBACKGROUND);
textLeft = left + TEXTMARGIN;
textRight = right - TEXTMARGIN;
textBottom = bottom + TEXTMARGIN;
textTop = top - TEXTMARGIN;
}
else if (bgColor)
{
SetObjectColor(bgColor);
FillRect(left, right, bottom, top);
textLeft = left + HANDLESIZE + 2;
textRight = right - HANDLESIZE - 2;
textBottom = bottom + HANDLESIZE + 2;
textTop = top - HANDLESIZE - 2;
}
else /* default is no inset */
{
textLeft = left;
textRight = right;
textBottom = bottom;
textTop = top;
}
SetClipRect(textLeft-1, textRight+1, textBottom-1, textTop+1);
if (uiTB)
{
SetUIFont(uiFont);
}
else
{
SetupFont(fontName, size);
}
length = StrWidth(text);
center = (textLeft + textRight)/2;
switch (align)
{
case CENTERALIGN:
lineStart = center - length/2;
break;
case RIGHTALIGN:
lineStart = textRight - length;
break;
case LEFTALIGN:
default:
lineStart = textLeft;
break;
}
if (active && AmICurrent(textBox) && style & EDITABLE)
{
/* find co-ords of beginning and end of selection (without offset) */
strncpy(textBuf, text, bgnSel);
textBuf[bgnSel] = '\0';
selStart = lineStart + StrWidth(textBuf);
if (bgnSel == endSel)
{
selEnd = selStart + 1;
}
else
{
int n = endSel - bgnSel;
strncpy(textBuf, text + bgnSel, n);
textBuf[n] = '\0';
selEnd = selStart + StrWidth(textBuf);
}
/* check horizontal offset, update if necessary */
showEnd = GetPredicate(textBox, FORWARDVECTOR);
/* NOTE: This variable is set in the PRESS and EDIT methods to
* indicate which end of the selection to show when auto-scrolling.
*/
if (showEnd) /* adjust offset to show the end of selection */
{
if (selEnd - horOffset < textLeft)
{
horOffset = selEnd - textLeft - 2;
theObj = NewInt(horOffset);
SetVar(textBox, HOROFFSET, theObj);
}
else if (selEnd - horOffset > textRight)
{
horOffset = selEnd - textRight + 2;
theObj = NewInt(horOffset);
SetVar(textBox, HOROFFSET, theObj);
}
}
else /* adust offset to show beginning of selection */
{
if (selStart - horOffset < textLeft)
{
horOffset = selStart - textLeft - 2;
theObj = NewInt(horOffset);
SetVar(textBox, HOROFFSET, theObj);
}
else if (selStart - horOffset > textRight)
{
horOffset = selStart - textRight + 2;
theObj = NewInt(horOffset);
SetVar(textBox, HOROFFSET, theObj);
}
}
/* draw text cursor or selection rectangle */
FillUIRect(selStart - horOffset, selEnd - horOffset,
textBottom, textTop, ChooseSelectionColor(textBox));
}
/* now draw the text */
if (color) SetObjectColor(color);
else SetUIColor(UITEXT);
switch (align)
{
case CENTERALIGN:
DrawAString(CENTERALIGN, center - horOffset, textTop - size, text);
break;
case RIGHTALIGN:
DrawAString(RIGHTALIGN, textRight - horOffset, textTop - size, text);
break;
case LEFTALIGN:
default:
DrawAString(LEFTALIGN, lineStart - horOffset, textTop - size, text);
break;
}
RestoreClipRect();
#endif
return ObjTrue;
}
static ObjPtr PressTextBox(textBox, mouseX, mouseY, flags)
ObjPtr textBox;
int mouseX, mouseY;
long flags;
{
#ifdef INTERACTIVE
ObjPtr theObj;
char *text, *t, *fontName, lineBuf[MAXLINE + 1];
int i, j, cj, l, n, width, length;
int uiFont, style, align, size, nLines, lineSpace;
Bool uiTB = false;
float x;
int y, mX, mY, offset[MAXNLINES * MAXLINE], lnx[3*(MAXNLINES + 1)];
int left, right, bottom, top, hCent, vCent;
int textLeft, textRight, textBot, textTop;
int tabWid, nTabs;
Get2DIntBounds(textBox, &left, &right, &bottom, &top);
/* return if mouse outside text box */
if (mouseX < left || mouseX > right || mouseY < bottom
|| mouseY > top) return ObjFalse;
/* get text parameters and scan text */
theObj = GetIntVar("PressTextBox", textBox, STYLE);
if (!theObj) style = PLAIN;
else style = GetInt(theObj);
MakeVar(textBox, VALUE);
theObj = GetVar(textBox, VALUE);
if (theObj) text = GetString(theObj);
else text = "\0";
theObj = GetVar(textBox, ALIGNMENT);
if (theObj) align = GetInt(theObj);
else align = LEFTALIGN;
theObj = GetVar(textBox, UIFONT);
if (theObj)
{
uiFont = GetInt(theObj);
size = uiFontInfo[uiFont].size;
uiTB = true;
}
else
{
theObj = GetStringVar("PressTextBox", textBox, TEXTFONT);
if (theObj) fontName = GetString(theObj);
else return ObjFalse;
theObj = GetIntVar("PressTextBox", textBox, TEXTSIZE);
if (theObj) size = GetInt(theObj);
else return ObjFalse;
}
theObj = GetVar(textBox, LINESPACE);
if (theObj) lineSpace = GetInt(theObj);
else lineSpace = 4 + size/3;
MakeVar(textBox, BACKGROUND);
/* adjust bounds for background or pit */
if (style & WITH_PIT)
{
textLeft = left + TEXTMARGIN;
textRight = right - TEXTMARGIN;
textBot = bottom + TEXTMARGIN;
textTop = top - TEXTMARGIN;
}
else if (style & ADJUSTABLE || GetVar(textBox, BACKGROUND))
{
textLeft = left + (HANDLESIZE + 2);
textRight = right - (HANDLESIZE + 2);
textBot = bottom + (HANDLESIZE + 2);
textTop = top - (HANDLESIZE + 2);
}
else
{
textLeft = left;
textRight = right;
textBot = bottom;
textTop = top;
}
width = textRight - textLeft;
if (uiTB)
{
SetUIFont(uiFont);
}
else
{
SetupFont(fontName, size);
}
tabWid = TABWID*ChrWidth('0');
/*
* Build two arrays to keep character positions of text.
* lnx[l] is the index of the first character of line l in text.
* offset[i] is the total horiz offset to the middle of character i in text.
*/
t = text; l = 0; nLines = 0; lnx[0] = 0; nTabs = 0; indent = 0; /* setup for loop */
do {
t = NextLine(t, width - indent, lineBuf);
lnx[++l] = t - text; /* index to first char of next line */
length = StrWidth(lineBuf);
/* figure out where line begins */
switch (align)
{
case CENTERALIGN:
x = (textLeft + textRight)/2 - length/2;
break;
case RIGHTALIGN:
x = textRight - length;
break;
case LEFTALIGN:
default:
x = textLeft + indent;
break;
}
/* build next line of char offsets */
for (i=lnx[l-1]; i<lnx[l]; ++i)
{
register int w;
if (text[i] == '\t')
{
w = x;
x = textLeft + ( indent = (++nTabs)*tabWid );
offset[i] = (x + w)/2;
}
else
{
w = ChrWidth(text[i]);
offset[i] = x + w/2;
x += w;
}
}
if (*t == '\n')
{
++t; /* paragraph */
indent = 0;
nTabs = 0;
}
if (l > MAXNLINES) break;
} while (*t);
nLines = l; /* number of lines of text */
if (!IsSelected(textBox) && !GetVar(textBox, BACKGROUND))
{
/* see if the click is actually on text; if not, no hit */
l = (textTop - mouseY)/(size + lineSpace);
if (l < 0 || l >= nLines)
{
return ObjFalse; /* above or below text */
}
if (mouseX < offset[lnx[l]] - ChrWidth(text[lnx[l]])
|| mouseX > offset[lnx[l+1]-1])
{
return ObjFalse; /* to left or right of text */
}
}
if (TOOL(flags) == T_HELP) /* help mode? */
{
ContextHelp(textBox);
return ObjTrue;
}
/* return if not active */
if (!GetPredicate(textBox, ACTIVATED)) return ObjTrue;
/* return if not editable or adjustable */
if (!(style & (EDITABLE | ADJUSTABLE))) return ObjTrue;
if (style & ADJUSTABLE) /* only adjustable TBs affect object selection */
{
if (!(flags & F_EXTEND) && !IsSelected(textBox))
{
/* new selection not already selected. Deselect the rest */
DeselectAll();
}
if ((flags & F_EXTEND) && IsSelected(textBox) && !AmICurrent(textBox))
{
/*Deselect*/
Select(textBox, false);
return ObjTrue;
}
else if (!IsSelected(textBox))
{
/*Must select it*/
Select(textBox, true);
}
}
MakeMeCurrent(textBox);
DrawMe(textBox);
hCent = (left + right)/2;
vCent = (bottom + top)/2;
if (style & ADJUSTABLE) /* see if click is in frame */
{
Bool ml, mr, mb, mt;
ml = mr = mb = mt = false;
if (mouseX < left + HANDLESIZE) /* on left side */
{
if (mouseY > top - HANDLESIZE) /* top-left handle */
mt = ml = true;
else if (mouseY < bottom + HANDLESIZE) /* bottom-left handle */
mb = ml = true;
else if (mouseY > vCent - HANDLESIZE/2 && mouseY < vCent + HANDLESIZE/2)
ml = true; /* middle-left handle */
else ml = mr = mb = mt = true; /* in frame */
}
else if (mouseX > right - HANDLESIZE) /* on right side */
{
if (mouseY > top - HANDLESIZE) /* top-right handle */
mt = mr = true;
else if (mouseY < bottom + HANDLESIZE) /* bottom-right handle */
mb = mr = true;
else if (mouseY > vCent - HANDLESIZE/2 && mouseY < vCent + HANDLESIZE/2)
mr = true; /* middle-right handle */
else ml = mr = mb = mt = true; /* in frame */
}
else if (mouseY < bottom + HANDLESIZE) /* on bottom */
{
/* already handled (heh heh) corners */
if (mouseX > hCent - HANDLESIZE/2 && mouseX < hCent + HANDLESIZE/2)
mb = true; /* bottom middle handle */
else ml = mr = mb = mt = true; /* in frame */
}
else if (mouseY > top - HANDLESIZE) /* on top */
{
/* already handled (heh heh) corners */
if (mouseX > hCent - HANDLESIZE/2 && mouseX < hCent + HANDLESIZE/2)
mt = true; /* middle top handle */
else ml = mr = mb = mt = true; /* in frame */
}
else /* not on incredibly fancy frame */
{
if (!(style & EDITABLE)) return ObjTrue;
}
SaveForUndo(textBox);
if (mr || ml || mb || mt) /* drag the incredibly fancy frame around */
{
/* I am greatly indebted to my friend and colleague, Eric Pepke,
for the following code. Any errors or obfuscations are his. */
int initX = mouseX, initY = mouseY;
int newLeft, newRight, newBottom, newTop;
int oldNewLeft, oldNewRight, oldNewBottom, oldNewTop;
newLeft = oldNewLeft = left;
newRight = oldNewRight = right;
newBottom = oldNewBottom = bottom;
newTop = oldNewTop = top;
while (Mouse(&mX, &mY) && (mX == initX) && (mY == initY));
DrawSkeleton(true);
while (Mouse(&mX, &mY))
{
if (ml) newLeft = left + mX - initX;
if (mr) newRight = right + mX - initX;
if (mb) newBottom = bottom + mY - initY;
if (mt) newTop = top + mY - initY;
if (flags & F_CONSTRAIN)
{
/*Grid drag*/
if (ml && mr && mb && mt)
{
/*Special case--whole object gridded
Only grid top left*/
int width, height;
width = newRight - newLeft;
height = newTop - newBottom;
newLeft = GRIDX(newLeft);
newRight = newLeft + width;
newTop = top - (GRIDY(top - newTop));
newBottom = newTop - height;
}
else
{
/*Normal case*/
if (ml) newLeft = GRIDX(newLeft);
if (mr) newRight = right - GRIDX(right - newRight);
if (mb) newBottom = GRIDY(newBottom);
if (mt) newTop = top - GRIDY(top - newTop);
}
}
if (ml && newLeft + 3 * HANDLESIZE > newRight)
newLeft = newRight - 3 * HANDLESIZE;
if (mr && newLeft + 3 * HANDLESIZE > newRight)
newRight = newLeft + 3 * HANDLESIZE;
if (mb && newBottom + 3 * HANDLESIZE > newTop)
newBottom = newTop - 3 * HANDLESIZE;
if (mt && newBottom + 3 * HANDLESIZE > newTop)
newTop = newBottom + 3 * HANDLESIZE;
if ((newLeft != oldNewLeft ||
newRight != oldNewRight ||
newBottom != oldNewBottom ||
newTop != oldNewTop) &&
newLeft < newRight &&
newBottom < newTop)
{
Set2DIntBounds(textBox,
newLeft, newRight, newBottom, newTop);
oldNewLeft = newLeft;
oldNewRight = newRight;
oldNewBottom = newBottom;
oldNewTop = newTop;
DrawMe(textBox);
}
}
DrawSkeleton(false);
if (logging)
{
char cmd[256];
MakeObjectName(tempStr, textBox);
sprintf(cmd, "set bounds %s [%d %d %d %d]\n",
tempStr, newLeft, newRight,
newBottom, newTop);
Log(cmd);
}
return ObjTrue;
}
}
/* click is in text. First reset LASTKEY to 'no previous character' state */
SetVar(textBox, LASTKEY, NewInt(-1));
/* SaveForUndo(textBox); */
if (flags & F_EXTEND)
{
i = GetInt(GetVar(textBox, GetPredicate(textBox, FORWARDVECTOR) ? BGNSEL : ENDSEL));
}
else
{
/* find line and character position of mouse down */
l = (textTop - mouseY)/(size + lineSpace);
if (l < 0) i = 0;
else if (l >= nLines)
{
i = lnx[nLines];
}
else
{
i=lnx[l];
while (offset[i] < mouseX && i<lnx[l+1]) ++i;
}
}
/* now track mouse and find line and char pos of end of selection */
/* auto-scroll horizontally if one-line text box */
mX = mouseX; mY = mouseY; /* setup for at least one loop */
cj = -1; /* force redraw first time */
do {
l = (textTop - mY)/(size + lineSpace);
if (l < 0) j = 0;
else if (l >= nLines)
{
j = lnx[nLines];
}
else
{
j=lnx[l];
while (offset[j] < mX && j<lnx[l+1]) ++j;
}
if (j != cj) /* selection has changed */
{
if (i > j) /* make sure bgnSel < endSel */
{
SetVar(textBox, BGNSEL, NewInt(j));
SetVar(textBox, ENDSEL, NewInt(i));
SetVar(textBox, FORWARDVECTOR, ObjFalse);
}
else
{
SetVar(textBox, BGNSEL, NewInt(i));
SetVar(textBox, ENDSEL, NewInt(j));
SetVar(textBox, FORWARDVECTOR, ObjTrue);
}
DrawMe(textBox);
cj = j; /* remember current position */
}
} while (Mouse(&mX, &mY));
if (i == j && flags & F_DOUBLECLICK)
{
/* select the word at insPt */
while (i > 0)
{
if (IsAlphaNum(text[i-1])) --i;
else break;
}
while (text[j] != '\0')
{
if (IsAlphaNum(text[j])) ++j;
else break;
}
SetVar(textBox, BGNSEL, NewInt(i));
SetVar(textBox, ENDSEL, NewInt(j));
}
#endif
return ObjTrue;
}
static ObjPtr PressOneLiner(textBox, mouseX, mouseY, flags)
ObjPtr textBox;
int mouseX, mouseY;
long flags;
{
#ifdef INTERACTIVE
ObjPtr theObj;
char *text, *fontName;
int i, j, cj, length, horOffset, w;
int uiFont, style, align, size, offset[MAXLINE];
Bool uiTB = false;
float x;
int mX, mY;
int left, right, bottom, top;
int textLeft, textRight, textBot, textTop;
Get2DIntBounds(textBox, &left, &right, &bottom, &top);
/* return if mouse outside text box */
if (mouseX < left || mouseX > right || mouseY < bottom
|| mouseY > top) return ObjFalse;
if (TOOL(flags) == T_HELP) /* help mode? */
{
ContextHelp(textBox);
return ObjTrue;
}
/* get text parameters and scan text */
theObj = GetIntVar("PressOneLiner", textBox, STYLE);
if (!theObj) style = PLAIN;
else style = GetInt(theObj);
/* return if not editable */
if (!(style & EDITABLE)) return ObjTrue;
/* return if not active */
if (!GetPredicate(textBox, ACTIVATED)) return ObjTrue;
MakeMeCurrent(textBox);
MakeVar(textBox, VALUE);
theObj = GetVar(textBox, VALUE);
if (theObj) text = GetString(theObj);
else text = "\0";
theObj = GetVar(textBox, ALIGNMENT);
if (theObj) align = GetInt(theObj);
else align = LEFTALIGN;
theObj = GetVar(textBox, UIFONT);
if (theObj)
{
uiFont = GetInt(theObj);
size = uiFontInfo[uiFont].size;
uiTB = true;
}
else
{
theObj = GetStringVar("PressOneLiner", textBox, TEXTFONT);
if (theObj) fontName = GetString(theObj);
else return ObjFalse;
theObj = GetIntVar("PressOneLiner", textBox, TEXTSIZE);
if (theObj) size = GetInt(theObj);
else return ObjFalse;
}
theObj = GetVar(textBox, HOROFFSET);
if (theObj) horOffset = GetInt(theObj);
else horOffset = 0;
MakeVar(textBox, BACKGROUND);
/* adjust bounds for background or pit */
if (style & WITH_PIT)
{
textLeft = left + TEXTMARGIN;
textRight = right - TEXTMARGIN;
textBot = bottom + TEXTMARGIN;
textTop = top - TEXTMARGIN;
}
else if (GetVar(textBox, BACKGROUND))
{
textLeft = left + (HANDLESIZE + 2);
textRight = right - (HANDLESIZE + 2);
textBot = bottom + (HANDLESIZE + 2);
textTop = top - (HANDLESIZE + 2);
}
else
{
textLeft = left;
textRight = right;
textBot = bottom;
textTop = top;
}
if (uiTB)
{
SetUIFont(uiFont);
}
else
{
SetupFont(fontName, size);
}
length = StrWidth(text);
/* figure out where line begins (without offset) */
switch (align)
{
case CENTERALIGN:
x = (textLeft + textRight)/2 - length/2;
break;
case RIGHTALIGN:
x = textRight - length;
break;
case LEFTALIGN:
default:
x = textLeft;
break;
}
for (i=0; text[i]; ++i)
{
w = ChrWidth(text[i]);
offset[i] = x + w/2;
x += w;
}
SetVar(textBox, LASTKEY, NewInt(-1)); /* no previous character */
if (flags & F_EXTEND)
{
i = GetInt(GetVar(textBox, GetPredicate(textBox, FORWARDVECTOR) ? BGNSEL : ENDSEL));
}
else
{
/* Find character position of mouse down */
for (i=0; text[i] && offset[i] - horOffset < mouseX; ++i) ;
}
/* track mouse and find char pos of end of selection */
mX = mouseX; mY = mouseY; /* setup for at least one loop */
cj = -1; /* forces redraw the first time */
do {
for (j=0; text[j] && offset[j] - horOffset < mX; ++j) ;
if (j != cj) /* selection has changed */
{
if (i > j) /* make sure bgnSel < endSel */
{
SetVar(textBox, BGNSEL, NewInt(j));
SetVar(textBox, ENDSEL, NewInt(i));
SetVar(textBox, FORWARDVECTOR, ObjFalse);
}
else
{
SetVar(textBox, BGNSEL, NewInt(i));
SetVar(textBox, ENDSEL, NewInt(j));
SetVar(textBox, FORWARDVECTOR, ObjTrue);
}
DrawMe(textBox);
cj = j;
horOffset = GetInt(GetVar(textBox, HOROFFSET));
}
} while (Mouse(&mX, &mY));
if (i == j && flags & F_DOUBLECLICK)
{
/* select the word at insPt */
while (i > 0)
{
if (IsAlphaNum(text[i-1])) --i;
else break;
}
while (text[j] != '\0')
{
if (IsAlphaNum(text[j])) ++j;
else break;
}
SetVar(textBox, BGNSEL, NewInt(i));
SetVar(textBox, ENDSEL, NewInt(j));
}
#endif
return ObjTrue;
}
int IsAlphaNum(c)
char c;
{
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <='9';
}
static ObjPtr EditTextBox(textBox, key, flags)
ObjPtr textBox;
int key;
long flags;
{
#ifdef INTERACTIVE
ObjPtr theObj, theText, theStyle, theInsPt, theEndSel;
char *text;
int i, j, len, style, insPt, endSel, lastKey;
int left, right, bottom, top;
if (!AmICurrent(textBox)) return ObjFalse; /* keyboard input not for me */
theStyle = GetIntVar("EditTextBox", textBox, STYLE);
if (!theStyle) return ObjTrue;
style = GetInt(theStyle);
if (!(style & EDITABLE)) return ObjTrue;
#if 0
Not really reliable enough yet
/*EMP Set up owner for faster redrawing*/
if (style & ADJUSTABLE)
{
ObjPtr parent;
parent = GetVar(textBox, PARENT);
if (parent)
{
if (key)
{printf("tempObscured is true\n");
SetVar(parent, TEMPOBSCURED, ObjTrue);
}
else
{printf("tempObscured is false\n");
SetVar(parent, TEMPOBSCURED, ObjFalse);
}
}
}
#endif
Get2DIntBounds(textBox, &left, &right, &bottom, &top);
/* adjust bounds */
if (style & WITH_PIT)
{
left += TEXTMARGIN;
right -= TEXTMARGIN;
bottom += TEXTMARGIN;
top -= TEXTMARGIN;
}
else if (style & ADJUSTABLE || GetVar(textBox, BACKGROUND))
{
left += HANDLESIZE + 2;
right -= HANDLESIZE + 2;
bottom += HANDLESIZE + 2;
top -= HANDLESIZE + 2;
}
theText = GetStringVar("EditTextBox", textBox, VALUE);
if (theText) text = GetString(theText);
else text = "\0";
if ((len = strlen(text)) > textBufSize) /* grow buffer */
{
textBuf = (char *) Realloc(textBuf, len + TEXTBUFFERINCR);
if (!textBuf) /* failed */
{
OMErr();
textBufSize = 0;
return NULLOBJ;
}
}
theObj = GetVar(textBox, LASTKEY);
if (theObj) lastKey = GetInt(theObj);
else lastKey = -1;
theInsPt = GetVar(textBox, BGNSEL);
if (!theInsPt) insPt = len;
else insPt = GetInt(theInsPt);
theEndSel = GetVar(textBox, ENDSEL);
if (!theEndSel) endSel = len;
else endSel = GetInt(theEndSel);
/* copy up to the insertion point */
for(i=0; i<insPt; ++i) textBuf[i] = text[i];
/* process every key press */
if (key == '\b' || key == '\177')
{
if (lastKey < 0 || lastKey != '\b')
{
SaveForUndo(textBox);
}
SetVar(textBox, LASTKEY, NewInt('\b'));
if (insPt == endSel && insPt > 0) /* delete character before insPt */
{
for(i = insPt, j = --insPt; i<len; ++i, ++j)
textBuf[j] = text[i];
textBuf[j] = '\0';
}
else /* just delete selection */
{
for(i = endSel, j = insPt; i < len; ++i, ++j)
textBuf[j] = text[i];
textBuf[j] = '\0';
}
SetVar(textBox, VALUE, NewString(textBuf));
SetVar(textBox, BGNSEL, NewInt(insPt));
SetVar(textBox, ENDSEL, NewInt(insPt));
SetVar(textBox, CHANGED, ObjTrue);
DrawMe(textBox);
}
else if (key == '\r')
{
if (style & ONE_LINE) /* check for ENTERMETHOD */
{
FuncTyp EnterMethod = GetMethod(textBox, ENTERMETHOD);
if (EnterMethod) EnterMethod(textBox);
}
else /* put newline into string at insertion point */
{
if (lastKey < 0 || lastKey == '\b')
{
SaveForUndo(textBox);
}
SetVar(textBox, LASTKEY, NewInt(key));
textBuf[insPt] = '\n';
for(i=insPt; i<len; ++i) textBuf[i+1] = text[i + endSel - insPt];
textBuf[len+1] = '\0';
SetVar(textBox, VALUE, NewString(textBuf));
SetVar(textBox, BGNSEL, NewInt(insPt + 1));
SetVar(textBox, ENDSEL, NewInt(insPt + 1));
SetVar(textBox, CHANGED, ObjTrue);
DrawMe(textBox);
}
}
else if (key == FK_LEFT_ARROW)
{
if (flags & F_EXTEND)
{
if (insPt == endSel) /* no selection */
{
SetVar(textBox, FORWARDVECTOR, ObjFalse); /* set backward direction */
}
if (!GetPredicate(textBox, FORWARDVECTOR))
{
if (insPt > 0) --insPt;
}
else
{
if (endSel > 0) --endSel;
}
}
else /* move insPt and endSel back */
{
if (insPt > 0) --insPt;
endSel = insPt;
}
if (insPt <= endSel)
{
SetVar(textBox, BGNSEL, NewInt(insPt));
SetVar(textBox, ENDSEL, NewInt(endSel));
}
else
{
SetVar(textBox, BGNSEL, NewInt(endSel));
SetVar(textBox, ENDSEL, NewInt(insPt));
}
SetVar(textBox, LASTKEY, NewInt(-1));
DrawMe(textBox);
}
else if (key == FK_RIGHT_ARROW)
{
if (flags & F_EXTEND)
{
if (insPt == endSel) /* no selection */
{
SetVar(textBox, FORWARDVECTOR, ObjTrue); /* set forward direction */
}
if (GetPredicate(textBox, FORWARDVECTOR))
{
if (endSel < len) ++endSel;
}
else
{
if (insPt < len) ++insPt;
}
}
else /* move endSel and insPt forward */
{
if (endSel < len) ++endSel;
insPt = endSel;
}
if (insPt <= endSel)
{
SetVar(textBox, BGNSEL, NewInt(insPt));
SetVar(textBox, ENDSEL, NewInt(endSel));
}
else
{
SetVar(textBox, BGNSEL, NewInt(endSel));
SetVar(textBox, ENDSEL, NewInt(insPt));
}
SetVar(textBox, LASTKEY, NewInt(-1));
DrawMe(textBox);
}
else if (key == FK_UP_ARROW || key == FK_DOWN_ARROW)
{
if (style & ONE_LINE)
{
/* just move to first or last char; scroll if necessary */
if (key == FK_UP_ARROW)
{
if (flags & F_EXTEND)
{
if (insPt == endSel) /* no selection */
SetVar(textBox, FORWARDVECTOR, ObjFalse); /* set backward direction */
if (GetPredicate(textBox, FORWARDVECTOR)) endSel = 0;
else insPt = 0;
}
else insPt = endSel = 0;
}
else
{
if (flags & F_EXTEND)
{
if (insPt == endSel) /* no selection */
SetVar(textBox, FORWARDVECTOR, ObjTrue); /* set forward direction */
if (GetPredicate(textBox, FORWARDVECTOR)) endSel = len;
else insPt = len;
}
else insPt = endSel = len;
}
if (insPt <= endSel)
{
SetVar(textBox, BGNSEL, NewInt(insPt));
SetVar(textBox, ENDSEL, NewInt(endSel));
}
else
{
SetVar(textBox, BGNSEL, NewInt(endSel));
SetVar(textBox, ENDSEL, NewInt(insPt));
}
SetVar(textBox, LASTKEY, NewInt(-1));
DrawMe(textBox);
}
else
{
/* Oh, so you want to move the cursor up or down, eh? Well,
we can do that, it's no bother. Really. So what if we have
to read all of the text and create a few arrays? We don't
mind. It's no trouble at all, really. Have a seat. */
int size, align, l, offset[MAXNLINES * MAXLINE], lnx[MAXNLINES + 1];
char *t, *fontName, lineBuf[MAXLINE + 1];
int uiFont, width, length, tabWid, nTabs;
float x;
Bool uiTB = false;
theObj = GetVar(textBox, ALIGNMENT);
if (theObj) align = GetInt(theObj);
else align = LEFTALIGN;
theObj = GetVar(textBox, UIFONT);
if (theObj)
{
uiFont = GetInt(theObj);
size = uiFontInfo[uiFont].size;
uiTB = true;
}
else
{
theObj = GetStringVar("EditTextBox", textBox, TEXTFONT);
if (theObj) fontName = GetString(theObj);
else return ObjFalse;
theObj = GetIntVar("EditTextBox", textBox, TEXTSIZE);
if (theObj) size = GetInt(theObj);
else return ObjFalse;
}
MakeVar(textBox, BACKGROUND);
width = right - left;
if (uiTB)
{
SetUIFont(uiFont);
}
else
{
SetupFont(fontName, size);
}
tabWid = TABWID*ChrWidth('0');
t = text; l = 0; lnx[0] = 0; indent = 0; /* setup for loop */
do {
t = NextLine(t, width - indent, lineBuf);
lnx[++l] = t - text; /* index to first char of next line */
length = StrWidth(lineBuf);
/* figure out where line begins */
switch (align)
{
case CENTERALIGN:
x = (left + right)/2 - length/2;
break;
case RIGHTALIGN:
x = right - length;
break;
case LEFTALIGN:
default:
x = left + indent;
break;
}
/* build next line of char offsets */
for (i=lnx[l-1]; i<lnx[l]; ++i)
{
register int w;
if (text[i] == '\t')
{
w = x;
x = left + ( indent = (++nTabs)*tabWid );
offset[i] = (x + w)/2;
}
else
{
w = ChrWidth(text[i]);
offset[i] = x + w/2;
x += w;
}
}
if (*t == '\n')
{
++t; /* paragraph */
indent = 0;
nTabs = 0;
}
if (l > MAXNLINES) break;
} while (*t);
/* find the line containing insPt */
for (i=1; i<=l; ++i) if (lnx[i] >= insPt) break;
/* line is i-1 */
if (key == FK_UP_ARROW)
{
int k;
if (i-1 == 0) return ObjTrue; /* already on first line */
for (k=lnx[i-2]; k<lnx[i-1]; ++k)
if (offset[k] > offset[insPt]) break;
SetVar(textBox, BGNSEL, theObj = NewInt(k));
SetVar(textBox, ENDSEL, theObj);
SetVar(textBox, LASTKEY, NewInt(-1));
DrawMe(textBox);
}
else if (key == FK_DOWN_ARROW)
{
int k;
if (i == l) return ObjTrue; /* already on last line */
for (k=lnx[i]; k<lnx[i+1]; ++k)
if (offset[k] > offset[insPt]) break;
SetVar(textBox, BGNSEL, theObj = NewInt(k));
SetVar(textBox, ENDSEL, theObj);
SetVar(textBox, LASTKEY, NewInt(-1));
DrawMe(textBox);
}
}
}
else if (key == '\0')
{
if (logging) LogControl(textBox);
ChangedValue(textBox);
/*** MakeMeCurrent(NULLOBJ); ***/
}
else if (key >= ' ' || key == '\t' && !(style & ONE_LINE))
{
if (lastKey < 0 || lastKey == '\b')
{
SaveForUndo(textBox);
}
SetVar(textBox, LASTKEY, NewInt(key));
if (style & ONE_LINE && len + 1 - (endSel - insPt) > MAXLINE)
return ObjTrue; /* no more text will fit */
/* add key at insertion point */
textBuf[insPt] = key;
for(i = endSel, j = ++insPt; i < len; ++i, ++j)
textBuf[j] = text[i];
textBuf[j] = '\0';
SetVar(textBox, VALUE, NewString(textBuf));
SetVar(textBox, BGNSEL, NewInt(insPt));
SetVar(textBox, ENDSEL, NewInt(insPt));
SetVar(textBox, CHANGED, ObjTrue);
DrawMe(textBox);
}
#endif
return ObjTrue;
}
/************************************************************ CUT, COPY, PASTE*/
static ObjPtr CutText(textBox)
ObjPtr textBox;
{
ObjPtr p, retVal;
int i, j, len, style, insPt, endSel;
char *text;
Bool deferChange;
if (p = GetStringVar("CutText", textBox, VALUE)) text = GetString(p);
else text = "\0";
len = strlen(text);
if (p = GetVar(textBox, BGNSEL)) insPt = GetInt(p);
else insPt = len;
if (p = GetVar(textBox, ENDSEL)) endSel = GetInt(p);
else endSel = len;
if (insPt == endSel) return NewString("\0");
SaveForUndo(textBox);
style = GetInt(GetVar(textBox, STYLE));
/* copy the selection to textBuf */
for (i=insPt, j=0; i<endSel; ++i, ++j) textBuf[j] = text[i];
textBuf[j] = '\0';
/* delete selection */
for (j=insPt, i=endSel; text[i]!='\0'; ++i, ++j) text[j] = text[i];
text[j] = '\0';
SetVar(textBox, VALUE, NewString(text));
SetVar(textBox, ENDSEL, NewInt(insPt));
SetVar(textBox, CHANGED, ObjTrue);
ChangedValue(textBox);
if (logging) LogControl(textBox);
ImInvalid(textBox);
retVal = NewString(textBuf);
ToClipboard(retVal);
return retVal;
}
static ObjPtr CopyText(textBox)
ObjPtr textBox;
{
ObjPtr p, retVal;
int i, j, len, insPt, endSel;
char *text;
if (p = GetStringVar("CopyText", textBox, VALUE))
text = GetString(p);
else text = "\0";
len = strlen(text);
if (p = GetVar(textBox, BGNSEL)) insPt = GetInt(p);
else insPt = len;
if (p = GetVar(textBox, ENDSEL)) endSel = GetInt(p);
else endSel = len;
/* copy the selection to textBuf */
for (i=insPt, j=0; i<endSel; ++i, ++j) textBuf[j] = text[i];
/* terminate and return */
textBuf[j] = '\0';
retVal = NewString(textBuf);
ToClipboard(retVal);
return retVal;
}
static ObjPtr PasteText(textBox)
ObjPtr textBox;
{
ObjPtr p;
int i, j, len, style, insPt, endSel;
char *text, *t;
Bool deferChange;
ObjPtr newText;
newText = FromClipboard();
if (!IsString(newText)) return NULLOBJ;
t = GetString(newText);
if (p = GetStringVar("PasteText", textBox, VALUE))
text = GetString(p);
else text = "\0";
len = strlen(text);
if (p = GetVar(textBox, BGNSEL)) insPt = GetInt(p);
else insPt = len;
if (p = GetVar(textBox, ENDSEL)) endSel = GetInt(p);
else endSel = len;
if ((len += strlen(t)) > textBufSize) /* grow buffer */
{
textBuf = (char *) Realloc(textBuf, len + TEXTBUFFERINCR);
if (!textBuf) /* failed */
{
OMErr();
textBufSize = 0;
return NULLOBJ;
}
}
style = GetInt(GetVar(textBox, STYLE));
if (style & ONE_LINE && len > MAXLINE) return NULLOBJ; /* won't fit */
SaveForUndo(textBox);
/* copy up to the insertion point */
for (i=0; i<insPt; ++i) textBuf[i] = text[i];
/* copy the paste text */
for (j=0; t[j]!='\0'; ++i, ++j) textBuf[i] = t[j];
insPt = i; /* remember new insertion point */
/* copy text after endSel */
for (j=endSel; text[j]!='\0'; ++i, ++j) textBuf[i] = text[j];
textBuf[i] = '\0';
SetVar(textBox, VALUE, NewString(textBuf));
SetVar(textBox, BGNSEL, p = NewInt(insPt));
SetVar(textBox, ENDSEL, p);
SetVar(textBox, CHANGED, ObjTrue);
ChangedValue(textBox);
if (logging) LogControl(textBox);
ImInvalid(textBox);
return NULLOBJ;
}
/********************************************************** SELECT ALL */
ObjPtr SelectAll(textBox)
ObjPtr textBox;
{
SetVar(textBox, BGNSEL, NewInt(0));
MakeVar(textBox, VALUE);
SetVar(textBox, ENDSEL, NewInt(strlen(GetString(GetVar(textBox,VALUE)))));
MakeMeCurrent(textBox);
return ObjTrue;
}
static ObjPtr TextBoxNotCurrent(textBox)
ObjPtr textBox;
/*Makes a textbox not current*/
{
ImInvalid(textBox);
SetVar(textBox, LASTKEY, NewInt(-1));
SetVar(textBox, HOROFFSET, NewInt(0));
}
/* adapted from ShowPaletteDisplayControls by Eric Pepke */
static ObjPtr ShowTextBoxControls(display, windowName)
ObjPtr display;
char *windowName;
/* Makes a new control window to control a textbox */
{
WinInfoPtr controlWindow;
ObjPtr var;
ObjPtr panel;
ObjPtr corral;
ObjPtr contents;
WinInfoPtr dialogExists;
dialogExists = DialogExists((WinInfoPtr) display, NewString("Controls"));
controlWindow = GetDialog((WinInfoPtr) display, NewString("Controls"), windowName,
TBPALWINWIDTH, TBPALWINHEIGHT, TBPALWINWIDTH,
TBPALWINHEIGHT, WINUI + WINFIXEDSIZE);
if (!dialogExists)
{
long info;
ObjPtr value;
ObjPtr checkBox, icon, name, colorBar, titleBox, textBox, button;
ObjPtr colorWheel, slider, radioGroup;
int left, right, bottom, top;
SetVar((ObjPtr) controlWindow, REPOBJ, display);
/*Set help string*/
SetVar((ObjPtr) controlWindow, HELPSTRING, NewString("This window \
shows controls for an annotation. For information about any of the controls \
in the window, use Help In Context on the control.\n"));
/*Add in a panel*/
GetWindowBounds(&left, &right, &bottom, &top);
panel = NewPanel(greyPanelClass, 0, right - left, 0, top - bottom);
if (!panel)
{
return NULLOBJ;
}
contents = GetVar((ObjPtr) controlWindow, CONTENTS);
PrefixList(contents, panel);
SetVar(panel, PARENT, (ObjPtr) controlWindow);
contents = GetVar(panel, CONTENTS);
/*Add in the group of controls for text color*/
left = MAJORBORDER;
top = TBPALWINHEIGHT - MAJORBORDER;
right = left + 4 * MAJORBORDER + COLORWHEELWIDTH + SLIDERWIDTH;
titleBox = NewTitleBox(left, right,
top - TITLEBOXTOP - MAJORBORDER - 2 * MINORBORDER - COLORWHEELWIDTH
- CHECKBOXHEIGHT - TEXTBOXHEIGHT - TEXTBOXSEP,
top, "Text");
SetVar(titleBox, PARENT, panel);
PrefixList(contents, titleBox);
left += MAJORBORDER;
right -= MAJORBORDER;
top -= TITLEBOXTOP + MAJORBORDER;
/*Make the color wheel*/
colorWheel = NewColorWheel(left, left + COLORWHEELWIDTH,
top - COLORWHEELWIDTH, top, "Text Color");
SetVar(colorWheel, PARENT, panel);
PrefixList(contents, colorWheel);
AssocColorControlWithVar(colorWheel, display, COLOR);
SetVar(colorWheel, HELPSTRING, NewString("This color wheel controls the \
hue and saturation of the color used to draw the text in the annotation. \
The final color is a combination of this hue and saturation and the value, or brightness, \
given by the Value slider."));
/*Make the text box below*/
textBox = NewTextBox(left, left + COLORWHEELWIDTH,
top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT,
top - COLORWHEELWIDTH - TEXTBOXSEP,
PLAIN, "Text Color Label", "Color");
SetVar(textBox, PARENT, panel);
PrefixList(contents, textBox);
SetTextAlign(textBox, CENTERALIGN);
/*Make the brightness slider*/
slider = NewSlider(right - SLIDERWIDTH, right,
top - COLORWHEELWIDTH, top,
PLAIN, "Text Color Value");
SetVar(slider, PARENT, panel);
PrefixList(contents, slider);
SetSliderRange(slider, 1.0, 0.0, 0.0);
AssocBrightnessControlWithVar(slider, display, COLOR);
SetVar(slider, HELPSTRING, NewString("This slider controls the \
value, or brightness, of the color used to draw the text in the annotation. \
The final color is a combination of this value and the hue and saturation \
given by the Color color wheel."));
/*Make the text box below*/
textBox = NewTextBox(right - SLIDERWIDTH - MAJORBORDER, right + MAJORBORDER,
top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT,
top - COLORWHEELWIDTH - TEXTBOXSEP,
PLAIN, "Text Value Label", "Value");
SetVar(textBox, PARENT, panel);
PrefixList(contents, textBox);
SetTextAlign(textBox, CENTERALIGN);
/*Make the background controls*/
top = TBPALWINHEIGHT - MAJORBORDER;
right = TBPALWINWIDTH - MAJORBORDER;
left = right - (4 * MAJORBORDER + COLORWHEELWIDTH + SLIDERWIDTH);
titleBox = NewTitleBox(left, right,
top - TITLEBOXTOP - MAJORBORDER - 2 * MINORBORDER - COLORWHEELWIDTH
- CHECKBOXHEIGHT - TEXTBOXHEIGHT - TEXTBOXSEP,
top, "Background");
SetVar(titleBox, PARENT, panel);
PrefixList(contents, titleBox);
left += MAJORBORDER;
right -= MAJORBORDER;
top -= TITLEBOXTOP + MAJORBORDER;
/*Make the color wheel*/
colorWheel = NewColorWheel(left, left + COLORWHEELWIDTH,
top - COLORWHEELWIDTH, top, "Background Color");
SetVar(colorWheel, PARENT, panel);
PrefixList(contents, colorWheel);
AssocColorControlWithVar(colorWheel, display, BACKGROUND);
SetVar(colorWheel, HELPSTRING, NewString("This color wheel controls the \
hue and saturation of the color used to draw the background of the annotation. \
The final color is a combination of this hue and saturation and the value, or brightness, \
given by the Value slider."));
/*Make the text box below*/
textBox = NewTextBox(left, left + COLORWHEELWIDTH,
top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT,
top - COLORWHEELWIDTH - TEXTBOXSEP,
PLAIN, "Background Color Label", "Color");
SetVar(textBox, PARENT, panel);
PrefixList(contents, textBox);
SetTextAlign(textBox, CENTERALIGN);
/*Make the brightness slider*/
slider = NewSlider(right - SLIDERWIDTH, right,
top - COLORWHEELWIDTH, top,
PLAIN, "Background Value");
SetVar(slider, PARENT, panel);
PrefixList(contents, slider);
SetSliderRange(slider, 1.0, 0.0, 0.0);
AssocBrightnessControlWithVar(slider, display, BACKGROUND);
SetVar(slider, HELPSTRING, NewString("This slider controls the \
value, or brightness, of the color used to draw the background of the annotation. \
The final color is a combination of this value and the hue and saturation \
given by the Color color wheel."));
/*Make the text box below*/
textBox = NewTextBox(right - SLIDERWIDTH - MAJORBORDER, right + MAJORBORDER,
top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT,
top - COLORWHEELWIDTH - TEXTBOXSEP,
PLAIN, "Background Value Label", "Value");
SetVar(textBox, PARENT, panel);
PrefixList(contents, textBox);
SetTextAlign(textBox, CENTERALIGN);
left -= MINORBORDER;
right += MINORBORDER;
/*Make the check box*/
top -= COLORWHEELWIDTH + TEXTBOXSEP + TEXTBOXHEIGHT + MINORBORDER;
checkBox = NewCheckBox(left, right,
top - CHECKBOXHEIGHT, top,
"No Background", true);
SetVar(checkBox, PARENT, panel);
PrefixList(contents, checkBox);
AssocInhibitControlWithVar(checkBox, display, BACKGROUND, NewInt(UIBLACK));
SetVar(checkBox, HELPSTRING, NewString("This checkbox controls whether \
a background is shown. If it is selected, no background is shown, and the \
objects behind can be seen."));
top -= CHECKBOXHEIGHT + MINORBORDER + MINORBORDER;
left = MAJORBORDER;
right = TBPALWINWIDTH - MAJORBORDER;
}
return (ObjPtr) controlWindow;
}
/************************************************************* LINE COUNT */
#ifdef PROTO
int LineCount(char *text, int width)
#else
int LineCount(text, width)
char *text;
int width;
#endif
{
char lineBuf[MAXLINE + 1];
int lineCount = 0;
int tabWid = TABWID*ChrWidth('0');
indent = 0;
do {
text = NextLine(text, width - indent, lineBuf);
if (*text == '\n')
{
++text;
indent = 0;
}
else indent += ChrCount(lineBuf, '\t')*tabWid;
if (*lineBuf == '\0') break; /* no text or width too small */
++lineCount;
} while (*text);
return lineCount;
}
/*************************************************************** NEXTLINE ******/
/* This function assembles words into line buffer from text buffer. It
returns a pointer to the next word in text or to terminator if done.
A newline indicates end of paragraph and terminates current line. The
return pointer points to the newline. All spaces are copied to the
new line except extra spaces that won't fit at the end of a line.
If a single word is too long for the line, it will be broken
after the last letter that fits. If the line buffer is not big enough
to hold the number of characters that will fit in the width given, the
line will be terminated after the last word that fits. Other than
newlines and soft eol (\r), no control characters should be in text.
1/21/92: indentation scheme added. Now the tab character can be included
in the text. There are fixed tab stops at multiples of TABWID * width
of a digit in the current font. The indentation is a function only of the
number of tabs, not the size of the text between tabs; to avoid overlapping
text, it may be necessary to use multiple tabs. After the last tab, wrapped
lines will continue to be indented to that tab stop until a newline is
encountered. NOTE: Indentation only applies to left-aligned text.
*/
static char *NextLine(text, width, line)
char *text; /* pointer into source text buffer */
int width; /* width of destination space in pixels */
char *line; /* line output buffer MAXLINE+1 chars long */
{
char *curWord;
int inSpace, tabWid, nTabs;
int totWid, n, m, spWid;
spWid = ChrWidth(' ');
tabWid = TABWID*ChrWidth('0');
curWord = text; /* point to beginning of current word in input text */
totWid = n = m = 0; /* reset offsets in output line */
nTabs = 0;
inSpace = true; /* reading space flag */
/* move words until:
-fill up line buffer
-width of characters in line buffer exceed given width
-run out of input text
-encounter newline
*/
while (n <= MAXLINE)
{
if (*text == '\r') /* "soft" EOL -- ignore */
{
++text;
}
else if (*text == ' ')
{
if (!inSpace)
{
/* the previous word fit; update fallback pointer */
m = n; /* where line will end if next word doesn't fit */
inSpace = true;
}
curWord = text++;
line[n++] = ' ';
totWid += spWid;
}
else if (*text == '\t') /* handle tab */
{
if (!inSpace)
{
m = n;
inSpace = true;
}
curWord = text++;
line[n++] = '\t';
totWid = (++nTabs)*tabWid;
}
else if (*text == '\n')
{
/* terminate line right here */
if (inSpace) line[m] = '\0';
else line[n] = '\0';
return text;
}
else if (*text == '\0')
{
/* terminate line right here */
if (inSpace) line[m] = '\0';
else line[n] = '\0';
return text;
}
else
{
/* non-space; move it */
totWid += ChrWidth(*text);
if (totWid > width) break;
if (inSpace) /* beginning new word */
{
curWord = text;
inSpace = false;
}
line[n++] = *text++;
}
}
if (m == 0 && !inSpace) /* single word too long for line */
{
/* look for a good place to break it */
char *b;
line[n] = '\0';
if ((b = strrchr(line, '/')) || (b = strrchr(line, '-')))
{
*(b + 1) = '\0';
return text - (line + n - (b + 1));
}
else
{
/* oh, well, this is a good place */
return text;
}
}
else
{
line[m] = '\0';
if (inSpace) /* skip to next word */
{
while (*curWord==' ') ++curWord;
}
return curWord;
}
}